home *** CD-ROM | disk | FTP | other *** search
/ Shareware Super Platinum 8 / Shareware Super Platinum 8.iso / mac / PROGTOOL / PASSDK30.ZIP;1 / DISK1.ZIP / PAS / SUBS / MIDI / MIDIA.ASM < prev    next >
Encoding:
Assembly Source File  |  1993-04-07  |  40.8 KB  |  1,780 lines

  1.  
  2. ;$Author:   DCODY  $
  3. ;$Date:   07 Apr 1993 07:49:22  $
  4. ;$Header:   X:/sccs/midi/midia.asv   1.9   07 Apr 1993 07:49:22   DCODY  $
  5. ;$Log:   X:/sccs/midi/midia.asv  $
  6. ;  
  7. ;     Rev 1.9   07 Apr 1993 07:49:22   DCODY
  8. ;  Silly! - I forgot to abort if the hardware was not detected!
  9. ;  
  10. ;     Rev 1.8   03 Feb 1993 12:03:04   DCODY
  11. ;  changed an OR that should have been an AND. Changed a bunch of JLE to
  12. ;  JB and one JLE that should have been an JB, which caused a buffer overrun.
  13. ;  
  14. ;     Rev 1.7   08 Dec 1992 16:51:22   DCODY
  15. ;  moved externADDR macro for Borland Link. Also, added valid
  16. ;  return codes for the init routine, which wasn't returning the
  17. ;  correct value.
  18. ;  
  19. ;     Rev 1.6   23 Sep 1992 10:34:44   DCODY
  20. ;  changed MVGetH... to mvGetH...
  21. ;  
  22. ;     Rev 1.5   04 Sep 1992 16:55:12   DCODY
  23. ;  NEAR external choked large model programs
  24. ;  
  25. ;     Rev 1.4   20 Jul 1992 11:42:44   DCODY
  26. ;  call to MVGetHWVersion requests active I/O detection. Found some
  27. ;  I/O that was not relocatable, and now performs XOR relocation.
  28. ;  
  29. ;     Rev 1.3   17 Jul 1992 13:57:30   DCODY
  30. ;  make I/O addresses relocatable.
  31. ;  
  32. ;     Rev 1.2   27 Jun 1992 15:44:56   DCODY
  33. ;  removed debug output code.
  34. ;  
  35. ;     Rev 1.1   25 Jun 1992 21:48:46   DCODY
  36. ;  PAS2 update
  37. ;  
  38. ;     Rev 1.0   15 Jun 1992 10:42:58   BCRANE
  39. ;  Initial revision.
  40. ;$Logfile:   X:/sccs/midi/midia.asv  $
  41. ;$Modtimes$
  42. ;$Revision:   1.9  $
  43. ;$Workfile:   midia.asm  $ 
  44.  
  45.         Title   MIDIA.ASM  --  Media Vision 3802 Midi Hardware Dependent Module
  46.     Subttl    Copyright (c) 1991,1992. Media Vision Inc. All Rights Reserved.
  47.     page    64,131
  48.  
  49. ;   /*\
  50. ;---|*|-----------------------====< MIDIA.ASM >====------------------------
  51. ;---|*|
  52. ;---|*| Low Level MIDI I/O routines for the Pro Audio Spectrum cards.
  53. ;---|*|
  54. ;   \*/
  55.  
  56.     .xlist
  57.     include model.inc
  58.     include masm.inc
  59.     include mvmidi.inc
  60.     include common.inc
  61.     include target.inc
  62.         .list
  63.  
  64. ;
  65. ;   /*\
  66. ;---|*|----====< int mvMIDIEnable >====----
  67. ;---|*|
  68. ;---|*| mvMIDIEnable - Initialize the MIDI interface
  69. ;---|*|
  70. ;---|*|   Entry Conditions:
  71. ;---|*|      wParm1 is a bit field for process control
  72. ;---|*|      D0 = 1 to enable input interrupts
  73. ;---|*|      D1 = 1 to enable output interrupts
  74. ;---|*|
  75. ;---|*|   Exit Conditions:
  76. ;---|*|      AX = -1 if cannot init the MIDI hardware.
  77. ;---|*|
  78. ;---|*|----====< void mvMIDIDisable >====----
  79. ;---|*|
  80. ;---|*| mxdDisable - MIDI shutdown
  81. ;---|*|
  82. ;---|*| Entry Conditions
  83. ;---|*|     None
  84. ;---|*|
  85. ;---|*| Exit Conditions
  86. ;---|*|     There is no return value.
  87. ;---|*|
  88. ;---|*|----====< int mvMIDIGetBuff >====----
  89. ;---|*|
  90. ;---|*| mvMIDIGetBuff - get data byte from MIDI channel
  91. ;---|*|
  92. ;---|*| Entry Conditions
  93. ;---|*|     wParm1 holds the count to move
  94. ;---|*|     dParm2 points to the target buffer
  95. ;---|*|
  96. ;---|*| Exit Conditions
  97. ;---|*|     AX = 0, no data, # of bytes moved
  98. ;---|*|
  99. ;---|*|----====< int mvMIDIGetByte >====----
  100. ;---|*|
  101. ;---|*| mvMIDIGetByte - get/check one byte from MIDI channel buffer
  102. ;---|*|
  103. ;---|*| Entry Conditions
  104. ;---|*|     None
  105. ;---|*|
  106. ;---|*| Exit Conditions
  107. ;---|*|     AX = byte, or -1 if no data
  108. ;---|*|
  109. ;---|*|----====< void mvMIDISendBuff >====----
  110. ;---|*|
  111. ;---|*| mvMIDISendBuff - send a buffer of data
  112. ;---|*|
  113. ;---|*| Entry Conditions
  114. ;---|*|     wParm1 = integer of count to load
  115. ;---|*|     dParm1 = far pointer to the buffer
  116. ;---|*|
  117. ;---|*| Exit Conditions
  118. ;---|*|     There is no return value.
  119. ;---|*|
  120. ;---|*|----====< void mvMIDISendByte >====----
  121. ;---|*|
  122. ;---|*| mvMIDISendByte - send data byte out MIDI channel
  123. ;---|*|
  124. ;---|*| Entry Conditions
  125. ;---|*|     wParm1  datum
  126. ;---|*|
  127. ;---|*| Exit Conditions
  128. ;---|*|     There is no return value.
  129. ;---|*|
  130. ;   \*/
  131. ;
  132.  
  133.     externADDR  mvGetHWVersion          ; determine the installed hardware type
  134.  
  135.     .data
  136. ;
  137. ;   /*\
  138. ;---|*|------------====< Global Data Definitions >====------------
  139. ;   \*/
  140. ;
  141.     extrn    _MVTranslateCode:word
  142.     extrn    _MVHWVersionBits:word
  143. ;
  144. ; The overflow count will always be here, but we won't make it public
  145. ; except for debugging purposes
  146. ;
  147.  
  148. ifdef DEBUG
  149.         public  _overflow
  150. endif
  151. _overflow       dw      0               ; overflow count
  152.  
  153. ;
  154. ; MidiInFilter allows certain types of MIDI messages to be tossed out...
  155. ;
  156. ;   NOTE: this currently works for active sense ONLY.
  157. ;
  158.     public    _MidiInFilter
  159. _MidiInFilter    dw    MF_ACTSENSE    ; default ignores active sense
  160.  
  161. ;
  162. ;   /*\
  163. ;---|*|------------====< Private Data Definitions >====------------
  164. ;   \*/
  165. ;
  166.  
  167. ;
  168. ; This midi code uses interrupt driven I/O, so a circular buffer is used
  169. ; to support the data flow.
  170. ;
  171.  
  172. MAXQUEUE    equ    128
  173.  
  174. ;
  175. ; MIDI input circular buffer
  176. ;
  177. iCircularQueue    db    MAXQUEUE    dup (0)
  178.  
  179. MIDIiQueueCnt    dw    0
  180.  
  181. lpiMIQueue    dw    iCircularQueue
  182. lpiMOQueue    dw    iCircularQueue
  183.  
  184. ;
  185. ; MIDI output circular buffer
  186. ;
  187. oCircularQueue    db    MAXQUEUE    dup (0)
  188.  
  189. MIDIoQueueCnt    dw    0
  190.  
  191. lpoMIQueue    dw    oCircularQueue
  192. lpoMOQueue    dw    oCircularQueue
  193.  
  194. ;
  195. ; Interrupt channel number and mask
  196. ;
  197.  
  198. _IRQNumb        db      -1
  199. _IRQMask    db    0
  200.  
  201. ;
  202. ; Interrupt Service Routine re-entrancy sema-phore
  203. ;
  204. ISRbusy         db      -1              ; ISR semaphore
  205.  
  206. ;
  207. ; Internal process control to handle polled or interrupt driven data I/O
  208. ;
  209. ProcessControl  db      0               ; Interrupt or polled I/O
  210. INTINPUT    equ    00000001b
  211. INTOUTPUT    equ    00000010b    ; (currently not implemented)
  212.  
  213.  
  214. ;
  215. ;   /*\
  216. ;---|*|------------====< Yamaha 3802 midi interface variables >====------------
  217. ;   \*/
  218. ;
  219.  
  220. MDctrl        db    0    ; MDSYSCTLR shadow for write only hardware
  221. ISRenab     db    0    ; R06 TX and RX int enable bits
  222.  
  223. ; r02/r03/r06 bit definitions
  224. TxIRQ    equ    01000000b    ; Tx FIFO interrupt
  225. RxIRQ    equ    00100000b    ; Rx FIFO interrupt
  226.  
  227. ; r34 bit definitions
  228. RxRDY    equ    10000000b    ; Rx FIFO non-empty
  229.  
  230. ; r54 bit definitions
  231. TxEMP    equ    10000000b    ; Tx FIFO empty
  232. TxRDY    equ    01000000b    ; Tx FIFO non-full
  233.  
  234. TIMER1    equ    2173
  235.  
  236. ;
  237. ;------------------------================================----------------------
  238. ;------------------------====< MIDI Common Routines >====----------------------
  239. ;------------------------================================----------------------
  240. ;
  241.         .code
  242.     assume    ds:@data,es:nothing
  243.  
  244. ;
  245. ; We will save the old IRQ vector here to guarrantee access at all times.
  246. ;
  247.  
  248. OldISR          dd      0               ; holds the original IRQ vector
  249.  
  250. ;
  251. ;    Toggle the MIDI interrupt to stimulate latent IRQs
  252. ;
  253. ToggleMV101mask macro
  254.  
  255.         mov     dx,INTRCTLR
  256.     xor    dx,[_MVTranslateCode]
  257.  
  258.     in    al,dx            
  259.     xor    al,bICmidi    ; disable MIDI interrupts
  260.     out    dx,al
  261.     pause
  262.     xor    al,bICmidi    ; enable MIDI interrupts
  263.     out    dx,al
  264.  
  265.     endm
  266.  
  267. ;
  268. ;   /*\
  269. ;---|*|----====< int mvMIDIEnable >====----
  270. ;---|*|
  271. ;---|*| Initialize the MIDI interface
  272. ;---|*|
  273. ;---|*| Entry Conditions:
  274. ;---|*|       wParm1 is a bit field for process control:
  275. ;---|*|      D0 = 1 to enable input interrupts.
  276. ;---|*|      D1 = 1 to enable output interrupts.
  277. ;---|*|
  278. ;---|*| Exit Conditions:
  279. ;---|*|     AX = -1 if cannot init the MIDI hardware.
  280. ;---|*|
  281. ;   \*/
  282. ;
  283.         public  mvMIDIEnable
  284. mvMIDIEnable   proc
  285.     push    bp            ; frame the stack for our 1 parameter
  286.     mov    bp,sp
  287. ;
  288. ; reset the MIDI buffering system
  289. ;
  290.     mov    [lpiMIQueue],OFFSET iCircularQueue
  291.     mov    [lpiMOQueue],OFFSET iCircularQueue
  292.     mov    [lpoMIQueue],OFFSET oCircularQueue
  293.     mov    [lpoMOQueue],OFFSET oCircularQueue
  294.     mov    [MIDIoQueueCnt],0
  295.     mov    [MIDIiQueueCnt],0
  296.     mov    [_overflow],0
  297.     mov    [_MidiInFilter],MF_ACTSENSE
  298. ;
  299. ; If the hardware bits have not been determined, do it...
  300. ;
  301.     cmp    _MVHWVersionBits,-1    ; version bits = -1 if the function
  302.     jnz    @F            ; hasn't been called yet.
  303.     mov    ax,USE_ACTIVE_ADDR    ; do the call
  304.     push    ax            ; to setup the hardware bits, etc.
  305.     call    mvGetHWVersion
  306.  
  307.         cmp     ax,-1                   ; is the hardware installed?
  308.     pop    ax
  309.     jz    mvmienbad        ; no, exit bad...
  310.  
  311.     ;
  312.     @@:
  313. ;
  314. ; determine the IRQ for the Pro Audio card
  315. ;
  316.     call    whereirq        ; looks for MVSOUND.SYS
  317. ;
  318. ; convert each bit to a full mask. Send this mask to each routine.
  319. ;
  320.     mov    ax,wParm1        ; load the bit flags
  321.     mov    [ProcessControl],al    ; save as our process control
  322.     ror    ax,1            ; ah holds input bit, al holds output
  323.     neg    ah
  324.     sbb    ah,ah            ; ah = FF to enable ints, else 0
  325.     neg    al
  326.     sbb    al,al            ; al = FF to enable ints, else 0
  327. ;
  328. ; perform the proper init
  329. ;
  330.     test    [_MVHWVersionBits],bMV101; MV101 version of MIDI?
  331.     jz    @F             ; no, go do yamaha
  332. ;
  333. ; initialize the MV101 MIDI device
  334. ;
  335.         call    enable_mv101
  336.     jc    mvmienbad        ; cannot set it up...
  337.     sub    ax,ax            ; return oky doky...
  338.     pop    bp
  339.         ret
  340. ;
  341. @@:
  342. ;
  343. ; initialize the Yamaha 3802
  344. ;
  345.         call    enable_yamaha
  346.     jc    mvmienbad        ; cannot set it up...
  347.     sub    ax,ax            ; return oky doky...
  348.         pop     bp
  349.         ret
  350. ;
  351. mvmienbad:
  352.     mov    ax,-1            ; exit bad...
  353.         pop     bp
  354.         ret
  355.  
  356. mvMIDIEnable   endp
  357.  
  358. ;
  359. ;   /*\
  360. ;---|*|----====< void mvMIDIDisable >====----
  361. ;---|*|
  362. ;---|*| MIDI device shutdown.
  363. ;---|*|
  364. ;---|*| Entry Conditions:
  365. ;---|*|     None.
  366. ;---|*|
  367. ;---|*| Exit Conditions:
  368. ;---|*|     There is no return value.
  369. ;---|*|
  370. ;   \*/
  371. ;
  372.         public  mvMIDIDisable
  373. mvMIDIDisable  proc
  374. ;
  375. ; remove ourselves from the chain
  376. ;
  377.         call    unhook_interrupt
  378. ;
  379. ; perform the proper init
  380. ;
  381.     test    [_MVHWVersionBits],bMV101; MV101 version of MIDI?
  382.     jz    @F             ; no, go do yamaha
  383.  
  384.     call    disable_MV101        ; disable the MV101 MIDI
  385.         ret
  386.     ;
  387.     @@:
  388.     call    disable_yamaha        ; disable the Yamaha MIDI
  389. ;
  390. midblexit:
  391.         ret
  392.  
  393. mvMIDIDisable  endp
  394.  
  395. ;
  396. ;   /*\
  397. ;---|*|----====< int mvMIDIGetBuff >====----
  398. ;---|*|
  399. ;---|*| Get data byte from MIDI channel.
  400. ;---|*|
  401. ;---|*| Entry Conditions
  402. ;---|*|     wParm1 holds the count to move.
  403. ;---|*|     dParm2 points to the target buffer.
  404. ;---|*|
  405. ;---|*| Exit Conditions
  406. ;---|*|     AX = 0, no data, # of bytes moved.
  407. ;---|*|
  408. ;   \*/
  409. ;
  410.         public  mvMIDIGetBuff
  411. mvMIDIGetBuff  proc
  412.     push    bp
  413.     mov    bp,sp
  414. ;
  415. ; save the C criticals
  416. ;
  417.         push    es
  418.     push    si
  419.     push    di
  420. ;
  421. ; load the parameters
  422. ;
  423.         mov     cx,wParm1               ; get the number of bytes to move
  424.     les    di,wParm2        ; get the target pointer
  425.     mov    si,[lpiMOqueue]     ; get the source pointer
  426.     sub    dx,dx            ; dx holds the # of bytes moved
  427.     cld
  428. ;
  429. ; using interrupt driven input?
  430. ;
  431.         test    [ProcessControl],INTINPUT
  432.     jz    mvigb_20        ; polled, check each h/w
  433. ;
  434. mvigb_05:
  435. ;
  436. ; read as many bytes out of the queues until one is empty, or full.
  437. ;
  438.     cmp    [MIDIiQueueCnt],0    ; all done?
  439.     jz    mvigb_10        ; yes, return # of bytes moved
  440.     movsb
  441.     dec    [MIDIiQueueCnt]     ; one less byte here...
  442.     inc    dx
  443.     cmp    si,offset iCircularQueue+MAXQUEUE
  444.     jb    @F
  445.     mov    si,offset iCircularQueue
  446.     ;
  447.     @@:
  448.     loop    mvigb_05        ; get it all...
  449. ;
  450. mvigb_10:
  451.     mov    [lpiMOQueue],si     ; save the pointer
  452.     mov    ax,dx
  453. ;
  454. mvigb_ret:
  455.     pop    di
  456.     pop    si
  457.     pop    es
  458.     pop    bp
  459.         ret
  460. ;
  461. mvigb_20:
  462. ;
  463. ; This is a little slow, but avoids messy code duplication
  464. ;
  465.     push    si            ; save si
  466.     mov    si,cx            ; si will be our loop counter
  467.     mov    bp,cx            ; bp will hold the total count
  468. ;
  469. mvigb_25:
  470.     call    FFAR ptr mvMIDIGetByte    ; get the next byte
  471.     cmp    ax,-1            ; any data?
  472.     jz    mvigb_30        ; nope, we're done...
  473.     stosb                ; save in the callers buffer
  474.     dec    si            ; all done?
  475.     jnz    mvigb_25        ; nope, continue looping
  476. ;
  477. mvigb_30:
  478.         sub     bp,si                   ; bp holds the total read count
  479.     mov    ax,bp
  480.     pop    si
  481.     jmp    short mvigb_ret
  482.  
  483. mvMIDIGetBuff  endp
  484.  
  485. ;
  486. ;   /*\
  487. ;---|*|----====< int mvMIDIGetByte >====----
  488. ;---|*|
  489. ;---|*| Get one byte from MIDI channel buffer.
  490. ;---|*|
  491. ;---|*| Entry Conditions
  492. ;---|*|     None.
  493. ;---|*|
  494. ;---|*| Exit Conditions
  495. ;---|*|     AX = -1 if no data.
  496. ;---|*|     AH =  0 if data in AL.
  497. ;---|*|
  498. ;   \*/
  499. ;
  500.         public  mvMIDIGetByte
  501. mvMIDIGetByte  proc
  502. ;
  503. ; If the code is running as interrupt input, then we can check the queue
  504. ;
  505.         test    [ProcessControl],INTINPUT
  506.     jz    mvgbt_20        ; polled, check each h/w
  507.  
  508.     cmp    [MIDIiQueueCnt],0    ; any data?
  509.     jz    mvgbt_none        ; no, just return now
  510.  
  511.     mov    bx,[lpiMOqueue]     ; get the source pointer
  512.     sub    ah,ah            ; clear out the top
  513.     mov    al,[bx]         ; load the bottom
  514.  
  515.     dec    [MIDIiQueueCnt]     ; one less byte here...
  516.     inc    bx
  517.     cmp    bx,offset iCircularQueue+MAXQUEUE
  518.     jb    mvgbt_05
  519.     mov    bx,offset iCircularQueue
  520. ;
  521. mvgbt_05:
  522.     mov    [lpiMOqueue],bx     ; save the new pointer
  523.         ret
  524. ;
  525. mvgbt_none:
  526.     mov    ax,-1            ; bad, so exit with error flag
  527.     ret
  528. ;
  529. mvgbt_20:
  530. ;
  531. ; This is the polled mode of MIDI input - go check the correct chip FIFO
  532. ;
  533.         test    [_MVHWVersionBits],bMV101; MV101 version of MIDI?
  534.     jz    mvgbt_yamaha         ; no, go do yamaha
  535. ;
  536. ; read the MV101 MIDI fifo
  537. ;
  538.     mov    dx,MIDISTATUS        ; check data available
  539.     xor    dx,[_MVTranslateCode]    ; translated I/O addr
  540.  
  541.     in    al,dx            ; isolate the data available bit
  542.     and    ax,bMSRififo
  543.     jz    mvgbt_none        ; no data available, go report it...
  544.  
  545.     mov    dx,MIDIDATA
  546.         xor     dx,[_MVTranslateCode]   ; translated I/O addr
  547.  
  548.     in    al,dx            ; return the byte in al, ah = 0
  549.  
  550.     ret
  551. ;
  552. mvgbt_yamaha:
  553. ;
  554. ; read the Yamaha 3802 MIDI fifo.
  555. ;
  556.         mov     al, 3                   ; 3x
  557.     mov    dx, MDSYSCTLR        ; set the 3802 global reg set index
  558.     mov    [MDctrl],al        ; shadow...
  559.     out    dx, al
  560.  
  561.         mov     dx, MDGROUP4            ; 34 = FIFO-Rx status
  562.     in    al, dx
  563.     and    ax, RxRDY        ; RxRDY bit?
  564.         jz      mvgbt_none              ; no data available, go report it...
  565.  
  566.     mov    dx, MDGROUP6        ; 36 = FIFO-Rx data
  567.  
  568.     in    al, dx            ; return the byte in al, ah = 0
  569.  
  570.     ret
  571.  
  572. mvMIDIGetByte  endp
  573.  
  574. ;
  575. ;   /*\
  576. ;---|*|----====< void mvMIDISendByte >====----
  577. ;---|*|
  578. ;---|*| mvMIDISendByte - send a MIDI data byte out the MIDI channel.
  579. ;---|*|
  580. ;---|*| Entry Conditions
  581. ;---|*|     wParm1 - MIDI byte to be sent.
  582. ;---|*|
  583. ;---|*| Exit Conditions
  584. ;---|*|     There is no return value.
  585. ;   \*/
  586. ;
  587.     public    mvMIDISendByte
  588. mvMIDISendByte    proc
  589. ;
  590. ; send the byte out directly if polled output, else queue it up to keep order
  591. ;
  592.         push    bp
  593.     mov    bp,sp
  594.  
  595.     mov    al,wParm1        ; grab the byte
  596.  
  597.     test    [ProcessControl],INTOUTPUT ; interrupt output?
  598.     jnz    mvsnd_ints           ; yes, we will queue it...
  599.  
  600.         call    dosendbyte              ; send it out straight
  601.  
  602.         pop     bp
  603.     ret
  604. ;
  605. mvsnd_ints:
  606. ;
  607. ; Interrupt driven output requires the byte be queue to keep the byte order.
  608. ;
  609.         mov     bx,[lpoMIQueue]         ; get the input-to-buffer pointer
  610. ;
  611. @@:
  612.     cmp    [MIDIoQueueCnt],MAXQUEUE; is the internal queue full?
  613.     jnz    @F            ; no, go load another byte
  614.     call    primexmit        ; make sure the xmitter is working
  615.     jmp    short @B        ; go wait for data to move
  616. ;
  617. @@:
  618.     mov    [bx],al
  619.     inc    bx
  620.     cmp    bx,offset oCircularQueue+MAXQUEUE ; wrapped?
  621.     jb    @F
  622.     mov    bx,offset oCircularQueue      ; yes, go back to the beginning
  623. ;
  624. @@:
  625.         mov     [lpoMIQueue],bx         ; save the new input-to-buffer pointer
  626.     inc    [MIDIoQueueCnt]     ; add one more into the FIFO
  627.  
  628.         call    primexmit               ; make sure the xmitter is working
  629.     pop    bp
  630.     ret
  631.  
  632. mvMIDISendByte endp
  633.  
  634. ;
  635. ;   /*\
  636. ;---|*|----====< void mvMIDISendBuff >====----
  637. ;---|*|
  638. ;---|*| mvMIDISendBuff - send a buffer of data.
  639. ;---|*|
  640. ;---|*| Entry Conditions
  641. ;---|*|     wParm1 = integer of count to load.
  642. ;---|*|     dParm1 = far pointer to the buffer.
  643. ;---|*|
  644. ;---|*| Exit Conditions
  645. ;---|*|     Returns when all the bytes are loaded in the circular queue.
  646. ;   \*/
  647. ;
  648.     public    mvMIDISendBuff
  649. mvMIDISendBuff    proc
  650.         push    bp
  651.     mov    bp,sp            ; 'C' frame
  652.  
  653.     push    es            ; save the 'C' criticals
  654.     push    si
  655. ;
  656. ; we will load the entire block into the FIFO. This even means waiting for the
  657. ; transmitter to empty enough data until we're done.
  658. ;
  659.     mov    cx,wParm1        ; get the buffer counter
  660.     les    si,wParm2        ; get the far pointer
  661.     mov    bx,[lpoMIQueue]     ; get the input-to-buffer pointer
  662. ;
  663. queueloop:
  664.     cmp    [MIDIoQueueCnt],MAXQUEUE; is the internal queue full?
  665.     jnz    @F            ; no, go load another byte
  666.     call    primexmit        ; make sure the xmitter is working
  667.     jmp    short queueloop
  668. ;
  669. @@:
  670.     lods    byte ptr es:[si]    ; get the next MIDI byte
  671.     mov    [bx],al
  672.     inc    bx
  673.     cmp    bx,offset oCircularQueue+MAXQUEUE ; wrapped?
  674.     jb    @F
  675.     mov    bx,offset oCircularQueue      ; yes, go back to the beginning
  676. ;
  677. @@:
  678.     inc    [MIDIoQueueCnt]     ; add one more into the FIFO
  679.     loop    queueloop        ; load all the bytes into the queue
  680.     mov    [lpoMIQueue],bx     ; save the new input-to-buffer pointer
  681. ;
  682. ; We've loaded the FIFO. if polling, call the output routine till done.
  683. ;
  684.     test    [ProcessControl],INTOUTPUT ; interrupt driven output?
  685.     jnz    sendbuffints           ; yes, force the xmitter to work
  686. ;
  687. ; this byte goes out the MV101
  688. ;
  689.     @@:
  690.     call    primexmit        ; make sure the xmitter is working
  691.     cmp    [MIDIoQueueCnt],0    ; any more queued up data?
  692.     jnz    @B            ; yes, stay here till sent...
  693.  
  694.     jmp    short sendbuffexit    ; all done, return home
  695. ;
  696. sendbuffints:
  697. ;
  698. ; make sure the xmitter is primed to generate interrupts
  699. ;
  700.     call    primexmit
  701. ;
  702. sendbuffexit:
  703.     pop    si
  704.     pop    es
  705.     pop    bp
  706.     ret
  707.  
  708. mvMIDISendBuff endp
  709.  
  710. ;
  711. ;---------------------------==============================---------------------
  712. ;---------------------------====< Local Subroutines > ====---------------------
  713. ;---------------------------==============================---------------------
  714. ;
  715.  
  716. ;
  717. ;   /*\
  718. ;---|*|----====< disable_MV101 >====----
  719. ;---|*|
  720. ;---|*| This routine will disable any MV101 MIDI
  721. ;---|*| interrupts and reset the tranceiver.
  722. ;---|*|
  723. ;---|*| Entry Conditions:
  724. ;---|*|     None.
  725. ;---|*|
  726. ;---|*| Exit Conditions:
  727. ;---|*|     AX, DX modified
  728. ;---|*|
  729. ;   \*/
  730. ;
  731. disable_MV101    proc    near
  732.  
  733.     mov    dx,MIDICONTROL        ; get the control address
  734.     xor    dx,[_MVTranslateCode]    ; translate the address
  735.  
  736.         sub     al,al                   ; flush all enables
  737.     out    dx,al            ; kill fifo irq
  738.  
  739.         ret
  740.  
  741. disable_MV101   endp
  742.  
  743. ;
  744. ;   /*\
  745. ;---|*|----====< disable_yamaha >====----
  746. ;---|*|
  747. ;---|*| This routine will disable any Yamaha MIDI
  748. ;---|*| interrupts and reset the tranceiver.
  749. ;---|*|
  750. ;---|*| Entry Conditions:
  751. ;---|*|     None.
  752. ;---|*|
  753. ;---|*| Exit Conditions:
  754. ;---|*|     AX, DX modified
  755. ;---|*|
  756. ;   \*/
  757. ;
  758. disable_yamaha  proc    near
  759. ;
  760. ; disable interrupts in the yamaha 3802
  761. ;
  762.     sub    ax, ax
  763.     mov    [MDctrl], al
  764.     mov    dx, MDSYSCTLR
  765.     out    dx, al            ; 0x
  766.  
  767.         mov     dx, MDGROUP6            ; 06 = IRQ enable request
  768.     out    dx, al
  769.  
  770.         .errnz  MDGROUP6-MDGROUP5-1
  771.  
  772.     dec    dx            ; 05 = IRQ mode control
  773.     out    dx, al
  774.  
  775.         ret
  776.  
  777. disable_yamaha    endp
  778.  
  779. ;
  780. ;   /*\
  781. ;---|*|----====< dosendbyte >====----
  782. ;---|*|
  783. ;---|*| A generic routine to send one byte out to the hardware.
  784. ;---|*|
  785. ;---|*| Entry Conditions;
  786. ;---|*|     AL holds the byte to be sent.
  787. ;---|*|
  788. ;---|*| Exit Conditions:
  789. ;---|*|     AX,BX,CX,DX modified.
  790. ;---|*|     Byte sent, no return value.
  791. ;---|*|
  792. ;   \*/
  793. ;
  794. dosendbyte      proc    near
  795. ;
  796. ; save the byte until we need it...
  797. ;
  798.         mov     ah,al                   ; ah holds the byte to send
  799. ;
  800. ; select the proper chip.
  801. ;
  802.         test    [_MVHWVersionBits],bMV101; MV101 version of MIDI?
  803.     jz    send_yamaha         ; no, go do yamaha
  804. ;
  805. ; this byte goes out the MV101
  806. ;
  807.     mov    dx, MIDIFIFOS        ; get the transmitter status
  808.         xor     dx,[_MVTranslateCode]   ; translated I/O addr
  809. ;
  810. ; we will only load up to 15 bytes in the output FIFO since a zero count
  811. ; means either 16 bytes free or 0 bytes free. By only loading 15 bytes max,
  812. ; we assume a zero means 16 bytes free.
  813. ;
  814.     in    al,dx            ; get the FIFO output free room count
  815.     and    al,bMFCofifo        ; isolate the count
  816.     jz    mvsendit        ; 16 bytes free
  817.     sub    cx,cx            ; we will do a timeout
  818.     ;
  819.     @@:
  820.     in    al, dx            ; get the FIFO counts
  821.     and    al, bMFCofifo        ; any room in the output FIFO?
  822.     cmp    al, 10h         ; one byte left in the FIFO?
  823.     loopz    @b            ; wait till there is more room
  824.     jcxz    deadtx            ; exit on a timeout
  825. ;
  826. mvsendit:
  827.     mov    dx, MIDIDATA        ; get the data output port
  828.         xor     dx,[_MVTranslateCode]   ; translated I/O addr
  829.  
  830.     mov    al, ah
  831.     out    dx, al            ; ship stuff...
  832. ;
  833. deadtx:
  834.         ret
  835. ;
  836. send_yamaha:
  837. ;
  838. ; this byte goes out the yamaha 3802
  839. ;
  840.         mov     al, 5                   ; 5x
  841.     mov    [MDctrl], al        ; shadow it...
  842.     mov    dx, MDSYSCTLR        ; get the port
  843.     out    dx, al            ; let'er rip...
  844.  
  845.     mov    dx, MDGROUP4        ; 54 = FIFO-Tx status
  846. ;
  847. @@:     in      al, dx
  848.     test    al, TxRDY        ; TxRDY bit?
  849.     jz    @b            ; ..jump if FIFO full
  850.  
  851.     mov    dl, LOW MDGROUP6    ; 56 = FIFO-Tx data
  852.     mov    al, ah
  853.     out    dx, al            ; ship datum
  854.  
  855.     ret
  856.  
  857. dosendbyte    endp
  858.  
  859. ;
  860. ;   /*\
  861. ;---|*|----====< enable_mv101 >====----
  862. ;---|*|
  863. ;---|*| Enable the MV101 tranceiver, and any appropriate interrupts
  864. ;---|*|
  865. ;---|*| Entry Conditions:
  866. ;---|*|     AH = FF to enable input interrupts
  867. ;---|*|     AL = FF to enable output interrupts
  868. ;---|*|
  869. ;---|*| Exit Conditions:
  870. ;---|*|     AX,BX,CX,DX modified.
  871. ;---|*|     Carry clear -- assumed to be good
  872. ;---|*|
  873. ;   \*/
  874. ;
  875. enable_mv101    proc    near
  876. ;
  877. ; build the correct mask bits in ah
  878. ;
  879.     and    ax,(bMCRenafifoi SHL 8) + bMCRenafifoo
  880.     or    ah,al            ; ah holds the enable bits
  881. ;
  882. ; do something to the test register
  883. ;
  884. ;;;    mov    dx,MIDITEST
  885. ;;;    xor    dx,[_MVTranslateCode]    ; translated I/O addr
  886. ;;;    mov    al,0FFh
  887. ;;;    out    dx,al
  888. ;
  889. ; setup the MIDI prescale
  890. ;
  891.         mov     dx,MIDIPRESCALE
  892.         xor     dx,[_MVTranslateCode]   ; translated I/O addr
  893.     mov    al,10h            ;
  894.     out    dx,al
  895. ;
  896. ; reset the fifos
  897. ;
  898.     mov    dx,MIDICONTROL
  899.     xor    dx,[_MVTranslateCode]    ; translated I/O addr
  900.     mov    al,bMCRrstfifoi+bMCRrstfifoo
  901.     out    dx,al            ; send the reset bits
  902.     mov    al,ah
  903.     out    dx,al            ; clear reset bits and set enables
  904. ;
  905. ; reset any present status bits
  906. ;
  907.         mov     dx,MIDISTATUS
  908.     xor    dx,[_MVTranslateCode]    ; translated I/O addr
  909.     mov    al,-1            ; reset all midi status bits
  910.     out    dx,al
  911. ;
  912. ; only enable the stuff if we're using interrupts
  913. ;
  914.     test    [ProcessControl],INTINPUT+INTOUTPUT
  915.     jz    enamv_done        ; no interrupts, just exit now...
  916. ;
  917. ; install the interrupt handling now
  918. ;
  919.     cli
  920.  
  921.     lea    ax,MV101_ISR
  922.     call    hook_interrupt        ; insert our routine
  923.  
  924.     sti
  925. ;
  926. enamv_done:
  927.     clc
  928.     ret
  929.  
  930. enable_mv101    endp
  931.  
  932. ;
  933. ;   /*\
  934. ;---|*|----====< enable_yamaha >====----
  935. ;---|*|
  936. ;---|*| Enable the Yamaha 3802 tranceiver, and any appropriate interrupts.
  937. ;---|*|
  938. ;---|*| Enable the 3802 Yamaha MIDI device
  939. ;---|*|     AH = FF to enable input interrupts.
  940. ;---|*|     AL = FF to enable output interrupts.
  941. ;---|*|
  942. ;---|*| Exit Conditions:
  943. ;---|*|     AX,BX,CX,DX modified.
  944. ;---|*|     Carry clear -- assumed to be good
  945. ;---|*|
  946. ;   \*/
  947. ;
  948. enable_yamaha    proc      near
  949. ;
  950. ; build the correct mask bits in ah
  951. ;
  952.     and    ax,(RxIRQ SHL 8)+ TxIRQ
  953.     or    al,ah            ; al holds the enable bits
  954.     push    ax            ; save the interrupt enable bits
  955. ;
  956. ; reset the 3802 midi chip
  957. ;
  958.     mov    al, 80h         ; master clear
  959.     mov    [MDctrl], al
  960.     mov    dx, MDSYSCTLR
  961.     out    dx, al
  962.  
  963.     mov    cx, 100
  964. @@:    in    al, dx            ; wait 32 TCLK
  965.     loop    @b
  966.  
  967.     xchg    ax,cx            ; load zero
  968.     out    dx,al            ; flush the reset bit
  969.  
  970.     mov    al, 6
  971.     mov    [MDctrl], al
  972.     out    dx, al            ; 6x
  973.     mov    dx, MDGROUP6        ; 66 = Click counter control
  974.     mov    al, 00000010b        ; Clock=1.0MHz, no click pulse
  975.     out    dx, al
  976.  
  977.     mov    al, 4
  978.     mov    [MDctrl], al
  979.     mov    dx, MDSYSCTLR
  980.     out    dx, al            ; 4x
  981.     mov    dx, MDGROUP4        ; 44 = Tx communication rate
  982.     mov    al, 00001000b        ; CLKM/32 = 31,250 bps
  983.     out    dx, al
  984.  
  985.     mov    al, 2
  986.     mov    [MDctrl], al
  987.     mov    dx, MDSYSCTLR
  988.     out    dx, al            ; 2x
  989.     mov    dx, MDGROUP4        ; 24 = Rx communication rate
  990.     mov    al, 00001000b        ; CLKM/32 = 31,250 bps
  991.     out    dx, al
  992.  
  993.     mov    al, 5
  994.     mov    [MDctrl], al
  995.     mov    dx, MDSYSCTLR
  996.     out    dx, al            ; 5x
  997.     mov    dx, MDGROUP5        ; 55 = FIFO-Tx control
  998.     mov    al, 10000101b        ; TxE
  999.     out    dx, al
  1000.  
  1001.     mov    al, 8
  1002.     mov    [MDctrl], al
  1003.     mov    dx, MDSYSCTLR
  1004.     out    dx, al            ; 8x
  1005.     mov    dx, MDGROUP4        ; 84 = General Timer LSB
  1006.     mov    ax, TIMER1
  1007.     out    dx, al
  1008.     mov    dx, MDGROUP5        ; 85 = General Timer MSB
  1009.     xchg    ah, al
  1010.     out    dx, al
  1011. ;
  1012. ; clear the FIFO-Rx
  1013. ;
  1014.     mov    al, 3            ; 35 = RCR: FIFO-Rx control
  1015.     mov    [MDctrl], al        ; bit 7 = clear FIFO-Rx
  1016.     mov    dx, MDSYSCTLR        ; bit 6 = clear RxOV flag
  1017.     out    dx, al            ; bit 4 = enable MIDI-clock filter
  1018.     mov    dx, MDGROUP5        ; bit 3 = clear BRK flag
  1019.     mov    al, 11001101b        ; bit 2 = clear RxOL flag
  1020.     out    dx, al            ; bit 1 = enable Address-hunter
  1021. ;
  1022. ; only enable the stuff if we're using interrupts
  1023. ;
  1024.     test    [ProcessControl],INTINPUT+INTOUTPUT
  1025.     jz    enayam_already        ; no interrupts, just exit now...
  1026. ;                    ; bit 0 = enable Receiver
  1027. ; initialize the 3802 chip IRQ system
  1028. ;
  1029.         sub     al, al
  1030.     mov    [MDctrl], al
  1031.     mov    dx, MDSYSCTLR
  1032.     out    dx, al            ; 0x
  1033.     mov    dx, MDGROUP5        ; 05 = IRQ mode control
  1034.     mov    al, 0011b        ; VE+VM
  1035.     out    dx, al
  1036. ;
  1037. ; initialize the board and motherboard IRQ systems
  1038. ;
  1039.         cli
  1040.  
  1041.         .errnz  MDGROUP6-MDGROUP5-1
  1042.         inc     dx
  1043.  
  1044.     pop    ax            ; get the interrupt enable bits
  1045.         out     dx, al
  1046.     mov    [ISRenab], al
  1047.  
  1048.         mov     dx, MDGROUP4            ; flush any pending IRQs
  1049.     mov    al, 0ffh
  1050.     out    dx,al
  1051. ;
  1052. ; hook the actual vector
  1053. ;
  1054.     lea    ax,Yamaha_ISR
  1055.         call    hook_interrupt
  1056.         sti
  1057.  
  1058.         clc
  1059.     ret
  1060. ;
  1061. enayam_already:
  1062.     pop    ax
  1063.     clc
  1064.     ret
  1065.  
  1066. enable_yamaha    endp
  1067.  
  1068. ;
  1069. ;   /*\
  1070. ;---|*|----====< hook_interrupt >====----
  1071. ;---|*|
  1072. ;---|*| Hook the Pro Audio hardware interrupt,
  1073. ;---|*| and enable the system interrupt.
  1074. ;---|*|
  1075. ;---|*| Entry Conditions:
  1076. ;---|*|     None.
  1077. ;---|*|
  1078. ;---|*| Exit Conditions:
  1079. ;---|*|     AX,BX,CX,DX modified.
  1080. ;---|*|
  1081. ;   \*/
  1082. ;
  1083. hook_interrupt  proc    near
  1084.         push    ds
  1085.     push    es
  1086.  
  1087.     cmp    wptr cs:[OldISR+2],0    ; any segment?
  1088.     jnz    midihooked        ; yes, we've hooked already
  1089.  
  1090.     push    ax            ; save the IRQ offset
  1091.  
  1092.     mov    ax, 3508h        ; DOS : get vector
  1093.     cmp    [_IRQNumb],7        ; 1st IRQ channel?
  1094.     jbe    @F
  1095.     mov    al,70h-8        ; 2nd IRQs start at 70H
  1096.     ;
  1097.     @@:
  1098.     add    al, [_IRQNumb]        ; IRQ
  1099.     push    ax            ; save the IRQ #
  1100.  
  1101.     int    21h            ; fetch the vector
  1102.  
  1103.     mov    wptr cs:[OldISR+0], bx    ; save original value
  1104.     mov    wptr cs:[OldISR+2], es
  1105.  
  1106.     pop    ax
  1107.         pop     dx                      ; get the actual offset
  1108.  
  1109.         push    ds                      ; save ds over the int call
  1110.     push    cs
  1111.     pop    ds            ; ds:dx point to the vector
  1112.     mov    ah, 25h         ; DOS : set vector
  1113.     int    21h
  1114.     pop    ds
  1115. ;
  1116. ; enable the Pro Audio IRQ channel
  1117. ;
  1118.     pushf
  1119.     cli
  1120. ;
  1121. ; address the correct IRQ controller
  1122. ;
  1123.     mov    dx,IRQ1MASKREG
  1124.     cmp    [_IRQNumb],7        ; 1st IRQ controller?
  1125.     jbe    @F            ; yes, continue on...
  1126.     mov    dx,IRQ2MASKREG        ; no, use the 2nd interrupt
  1127.     ;
  1128.     @@:
  1129. ;
  1130. ; Enable the correct IRQ channel
  1131. ;
  1132.         in      al, dx                  ; enable the system IRQ
  1133.     mov    ah, [_IRQMask]
  1134.     not    ah
  1135.     and    al, ah
  1136.     out    dx, al
  1137. ;
  1138. ; Enable the Pro Audio MIDI interrupt
  1139. ;
  1140.     mov    dx, INTRCTLR        ; Enable the PAS. This could signal
  1141.     xor    dx, [_MVTranslateCode]
  1142.     in    al, dx            ; an interrupt immediately.
  1143.     or    al, bICmidi        ; MIDI interrupt enable
  1144.     out    dx, al
  1145.  
  1146.     popf
  1147.     ;
  1148.     midihooked:
  1149.  
  1150.         pop     es
  1151.     pop    ds
  1152.     ret
  1153.  
  1154. hook_interrupt  endp
  1155.  
  1156. ;
  1157. ;   /*\
  1158. ;---|*|----====< void primexmit >====----
  1159. ;---|*|
  1160. ;---|*| Prime the transmitter. If interrupt driven output, make sure the
  1161. ;---|*| outbound FIFO has at least one byte loaded. If polled, send
  1162. ;---|*| the next polled byte.
  1163. ;---|*|
  1164. ;---|*| Entry Conditions:
  1165. ;---|*|    Working registers assumed to hold data.
  1166. ;---|*|
  1167. ;---|*| Exit Conditions:
  1168. ;---|*|    No registers modified.
  1169. ;---|*|
  1170. ;   \*/
  1171. ;
  1172. primexmit    proc    near
  1173. ;
  1174. ; save everything for the caller
  1175. ;
  1176.     pushf                ; save the flags so we can CLI
  1177.     push    ax            ; don't mess with any other registers
  1178.     push    dx
  1179.         push    bx
  1180.     push    cx
  1181. ;
  1182. ; Interrupt driven output is a special case. We just have to prime the pump...
  1183. ;
  1184.     test    [ProcessControl],INTOUTPUT ; interrupt driven output?
  1185.     jnz    prixmints           ; yes, force the xmitter to work
  1186. ;
  1187. prixprimeit:
  1188. ;
  1189. ; This is polled output mode. We just send one byte out. The caller will keep
  1190. ; calling us till the queue is emptied.
  1191. ;
  1192.     cmp    [MIDIoQueueCnt],0    ; any data to send?
  1193.     jz    prixdone        ; no, it's all loaded and gone..
  1194.  
  1195.         mov     bx,[lpoMOQueue]         ; get the out-of-buffer pointer
  1196.     mov    al,[bx]
  1197.     inc    bx
  1198.  
  1199.     cmp    bx,offset oCircularQueue+MAXQUEUE ; wrapped?
  1200.     jb    @F
  1201.     mov    bx,offset oCircularQueue      ; yes, wrap it...
  1202. ;
  1203. @@:
  1204.     mov    [lpoMOQueue],bx     ; save the new input-to-buffer pointer
  1205.     dec    [MIDIoQueueCnt]     ; add one more into the FIFO
  1206.  
  1207.     call    dosendbyte        ; send it via the polled routines
  1208. ;
  1209. prixdone:
  1210. ;
  1211. ; return with nothing changed
  1212. ;
  1213.         pop     cx
  1214.     pop    bx
  1215.     pop    dx
  1216.     pop    ax
  1217.     popf
  1218.     ret
  1219. ;
  1220. prixmints:
  1221. ;
  1222. ; in case of some MIDI interrupts occuring when we don't expect it, (such
  1223. ; as MIDI in interrupts) this section will be executed without interrupts
  1224. ; to avoid double sending, or sending data from the queue out of order.
  1225. ;
  1226.     cli                ; no ints while we go to prime the pump
  1227. ;
  1228. ; Make sure the transmitter FIFO has data loaded. This guarrantees an interrupt
  1229. ; when the FIFO is empty.
  1230. ;
  1231.     test    [_MVHWVersionBits],bMV101; MV101 version of MIDI?
  1232.     jz    prixyamaha         ; no, go do yamaha
  1233.  
  1234.     mov    dx, MIDIFIFOS        ; get the transmitter FIFO status
  1235.         xor     dx,[_MVTranslateCode]   ; translated I/O addr
  1236.  
  1237.         in      al,dx                   ; get the FIFO output free room count
  1238.     and    al,bMFCofifo        ; isolate the outbound count
  1239.     jnz    prixdone        ; there is data, no need to prime it.
  1240.     jmp    short prixprimeit    ; 16 bytes free - load one more...
  1241. ;
  1242. prixyamaha:
  1243. ;
  1244. ; Yamaha 3802 - we go to TX register set 05 to find the TX empty bit
  1245. ;
  1246.     mov    al, 5            ; reg set 5x is for the xmitter
  1247.     mov    [MDctrl], al
  1248.     mov    dx, MDSYSCTLR
  1249.     out    dx, al            ; 5x
  1250.  
  1251.         mov     dx, MDGROUP4            ; 84 = General Timer LSB
  1252.     in    al,dx
  1253.     test    al,TxEMP        ; is the transmitter empty?
  1254.     jnz    prixprimeit        ; yes, go load another byte
  1255.     jmp    short prixdone        ; no, leave it alone
  1256.  
  1257. primexmit    endp
  1258.  
  1259. ;
  1260. ;   /*\
  1261. ;---|*|----====< unhook_interrupt >====----
  1262. ;---|*|
  1263. ;---|*| If installed, disable the IRQ system, then unhook
  1264. ;---|*| the Pro Audio IRQ handler from the chain.
  1265. ;---|*|
  1266. ;---|*| Entry Conditions:
  1267. ;---|*|    None.
  1268. ;---|*|
  1269. ;---|*| Exit Conditions:
  1270. ;---|*|    AX,BX,CX,DX may be modified.
  1271. ;---|*|
  1272. ;   \*/
  1273. ;
  1274. unhook_interrupt        proc    near
  1275. ;
  1276. ; don't do this if there is no need
  1277. ;
  1278.     cmp    wptr cs:[OldISR+2],0    ; interrupt already unhooked?
  1279.     jz    unhooked        ; yes, just exit
  1280. ;
  1281. ; disable system interrupt for the Pro Audio card
  1282. ;
  1283.     pushf
  1284.         cli
  1285.  
  1286.     test    al,fICintmaskbits    ; any other interrupts enabled
  1287.     jnz    mskint_done        ; yes, leave the system mask alone
  1288.  
  1289.     mov    dx,IRQ1MASKREG
  1290.     cmp    [_IRQNumb],7        ; 1st IRQ controller?
  1291.     jbe    @F            ; yes, continue on...
  1292.     mov    dx,IRQ2MASKREG        ; no, use the 2nd interrupt
  1293.     ;
  1294.     @@:
  1295.     cmp    [_IRQNumb],2        ; hardware IRQ 2?
  1296.     jz    mskint_done        ; yes, never mask it
  1297.  
  1298.     in    al,dx
  1299.     or    al,[_IRQMask]        ; no, kill the system interrupts
  1300.     out    dx,al
  1301. ;
  1302. mskint_done:
  1303.     mov    dx, INTRCTLR        ; disable the Pro Audio MIDI IRQ
  1304.     xor    dx, [_MVTranslateCode]
  1305.     in    al, dx
  1306.     and    al, not bICmidi     ; MIDI interrupt disable
  1307.     out    dx, al
  1308.  
  1309.     popf
  1310. ;
  1311. ; calculate the correct vector and restore it.
  1312. ;
  1313.     mov    ax, 2508h        ; DOS : set vector
  1314.     cmp    [_IRQNumb],7        ; 1st IRQ channel?
  1315.     jbe    @F
  1316.     mov    al,70h-8        ; 2nd IRQs start at 70H
  1317.     ;
  1318.     @@:
  1319.     add    al, [_IRQNumb]        ; IRQ
  1320. ;
  1321. ; do it through DOS...
  1322. ;
  1323.         push    ds
  1324.     lds    dx, cs:[OldISR]
  1325.     int    21h
  1326.     pop    ds
  1327.  
  1328.     mov    wptr cs:[OldISR+2],0    ; flush the segment of the vector
  1329. ;
  1330. unhooked:
  1331.         ret
  1332.  
  1333. unhook_interrupt    endp
  1334.  
  1335. ;
  1336. ;   /*\
  1337. ;---|*|----====< whereirq >====----
  1338. ;---|*|
  1339. ;---|*| This routine queries MVSOUND.SYS for the Pro Audio IRQ. Once
  1340. ;---|*| determined, then an appropriate interrupt mask will be
  1341. ;---|*| generated, and saved for future reference.
  1342. ;---|*|
  1343. ;---|*| Entry Conditions:
  1344. ;---|*|    None.
  1345. ;---|*|
  1346. ;---|*| Exit Conditions:
  1347. ;---|*|    AX,BX,CX,DX may be modified.
  1348. ;---|*|
  1349. ;   \*/
  1350. ;
  1351. whereirq        proc    near
  1352. ;
  1353. ; Do this just once
  1354. ;
  1355.     cmp    [_IRQNumb],-1        ; have we been through here?
  1356.     jnz    IRQdone         ; yes, it's been found
  1357. ;
  1358. ; Call MVSOUND.SYS to get the DMA/IRQ
  1359. ;
  1360.     mov    ax,0bc04h        ; call MVSOUND.SYS for it...
  1361.     int    2fh
  1362. ;
  1363. ; register the IRQ if the call was good
  1364. ;
  1365.     cmp    ax,'MV'                 ; was this a good call?
  1366.     jnz    IRQdone
  1367.  
  1368.     mov    [_IRQNumb],cl        ; save the #
  1369.     mov    ax,1
  1370.     shl    ax,cl
  1371.     or    al,ah
  1372.     mov    [_IRQMask],al        ; save the mask.
  1373. ;
  1374. IRQdone:
  1375.     ret
  1376.  
  1377. whereirq        endp
  1378.  
  1379. ;
  1380. ;------------------------===================================-------------------
  1381. ;------------------------====< MIDI Interrupt Service > ====-------------------
  1382. ;------------------------===================================-------------------
  1383. ;
  1384.  
  1385. ;
  1386. ;   /*\
  1387. ;---|*|----====< MV101_ISR >====----
  1388. ;---|*|
  1389. ;---|*|  ISR service routine for the MV101 MIDI interrupts.
  1390. ;---|*|
  1391. ;   \*/
  1392. ;
  1393. MV101_ISR    proc    far
  1394.     push    ds
  1395.     push    ax
  1396.     push    bx
  1397.     push    cx
  1398.     push    dx
  1399.  
  1400.     mov    ax,@data
  1401.     mov    ds,ax
  1402. ;
  1403. ; first time in, check for a MIDI interrupt
  1404. ;
  1405.     mov    dx,INTRCTLRST
  1406.     xor    dx,[_MVTranslateCode]    ; translate the address
  1407.  
  1408.     in    al,dx            ; get the interrupt status
  1409.     test    al,bISmidi        ; is this our interrupt?
  1410.     jnz    mv_is_midi_int        ; yes, go process it...
  1411.  
  1412.     test    al,fISints        ; are any of these interrupt legit?
  1413.     jjz    midiint_done        ; no, flush this int.
  1414. ;
  1415. ; this was not our interrupt, chain on...
  1416. ;
  1417.     pop    dx
  1418.     pop    cx
  1419.     pop    bx
  1420.         pop     ax
  1421.     pop    ds
  1422.     jmp    dword ptr cs:[OldISR]    ; pass off to the other code.
  1423. ;
  1424. mv_is_midi_int:
  1425. ;
  1426. ; check the receiver for data, or errors
  1427. ;
  1428.     mov    dx,MIDISTATUS
  1429.     xor    dx,[_MVTranslateCode]        ; translate the address
  1430.     in    al,dx
  1431.     mov    ah,al                ; save a copy for xmitter
  1432.  
  1433.     and    al,bMSRframeerr+bMSRififoovr+bMSRofifoovr ; overrun or frame error?
  1434.     jz    mvmidi_int            ; nope
  1435.     out    dx,al                ; clear errors
  1436.  
  1437.     mov    dx,MIDICONTROL
  1438.     xor    dx,[_MVTranslateCode]        ; translate the address
  1439.  
  1440.     in    al,dx
  1441.     or    al,bMCRrstfifoi+bMCRrstfifoo    ; reset FIFO in ptr
  1442.         out     dx,al
  1443.     and    al,NOT(bMCRrstfifoi+bMCRrstfifoo)
  1444.     out    dx,al
  1445. ;
  1446. mvmidi_int:
  1447. ;
  1448. ; get the status once again for the second chance loop
  1449. ;
  1450.         mov     dx,MIDISTATUS
  1451.     xor    dx,[_MVTranslateCode]    ; translate the address
  1452.     in    al,dx
  1453. ;
  1454. ; Only process the interrupt process wanted by the user
  1455. ;
  1456.     test    [ProcessControl],INTINPUT ; interrupt driven input?
  1457.     jz    checktrans        ; no, go check for int driven xmit
  1458.  
  1459.     test    al,bMSRififo        ; any data in input FIFO?
  1460.     jz    checktrans        ; no, go check the transmitter
  1461.  
  1462.     .errnz    MIDIFIFOS-MIDISTATUS-1
  1463.  
  1464.     inc    dx            ; move to the status register
  1465.  
  1466.     in    al,dx
  1467.     mov    cl,al
  1468.     and    cx,bMFCififo        ; get # of bytes in FIFO
  1469.     jnz    @F
  1470.     mov    cx,16
  1471.     ;
  1472.     @@:
  1473.     mov    dx,MIDIDATA        ; move to the data register
  1474.     xor    dx,[_MVTranslateCode]    ; translate the address
  1475.     mov    bx,[lpiMIQueue]     ; get  the input queue pointer
  1476. ;
  1477. mvrxloop:
  1478. ;
  1479. ; read the data off the receiver
  1480. ;
  1481.     in    al,dx            ; fetch the received byte
  1482. ;
  1483. ; MIDI spec requires transmitter send something every 300 msec
  1484. ; Active Sense (FE) is the standard "nothing for you" byte
  1485. ;
  1486.     test    [_MidiInFilter],MF_ACTSENSE ; filter out active sense
  1487.     jz    @F            ; no, keep it...
  1488.     cmp    al, 0FEh        ; Active Sense?
  1489.     je    rxCont            ; ..ignore it
  1490.     ;
  1491.     @@:
  1492.     cmp    [MIDIiQueueCnt],MAXQUEUE; is it full?
  1493.     jb    @F            ; no, save it
  1494.     inc    [_overflow]        ; yes, list it as an error
  1495.     jmp    short mvrxloop
  1496.     ;
  1497.     @@:
  1498.     mov    [bx],al
  1499.     inc    bx
  1500.     inc    [MIDIiQueueCnt]     ; one more in...
  1501.     cmp    bx,offset iCircularQueue+MAXQUEUE
  1502.     jb    rxCont
  1503.     mov    bx,offset iCircularQueue
  1504.     ;
  1505.     rxCont:
  1506.     loop    mvrxloop        ; do all bytes listed in the queue
  1507.     mov    [lpiMIQueue],bx     ; save the input queue pointer
  1508.     jmp    second_check        ; make sure FIFO is empty
  1509. ;
  1510. checktrans:
  1511. ;
  1512. ; If we are using interrupt driven output, load the FIFO now...
  1513. ;
  1514.     test    [ProcessControl],INTOUTPUT; interrupt driven output?
  1515.     jz    second_check          ; no, just exit out
  1516.  
  1517.     ; reset the interrupt now.
  1518.  
  1519.         mov     dx,MIDISTATUS
  1520.     xor    dx,[_MVTranslateCode]    ; translate the address
  1521.     mov    al,bMSRofifo        ; any data in output FIFO?
  1522.     out    dx,al
  1523.  
  1524.         ; check for any outgoing data
  1525.  
  1526.     cmp    [MIDIoQueueCnt],0    ; any queued up data?
  1527.     jz    second_check        ; no, just exit out
  1528.  
  1529.     mov    dx,MIDIFIFOS
  1530.     xor    dx,[_MVTranslateCode]    ; translate the address
  1531.  
  1532.         in      al,dx
  1533.     and    ax,bMFCofifo        ; get # of outgoing bytes
  1534.     mov    cl,4
  1535.     shr    al,cl            ; right hand justify the number
  1536.     xchg    ax,cx
  1537.     cmp    cl,1            ; down to 1 byte free?
  1538.     je    second_check        ; yes, can't load it
  1539.     ja    @F            ; we have 15 or less entries
  1540.     mov    cx,16            ; 16 entires fit, but...
  1541.     ;
  1542.     @@:
  1543.     dec    cx            ; we only load 15...
  1544.     mov    dx,MIDIDATA        ; move to the data register
  1545.     xor    dx,[_MVTranslateCode]    ; translate the address
  1546.     mov    bx,[lpoMOQueue]     ; get  the input queue pointer
  1547.     ;
  1548.     txLoop:
  1549.     mov    al,[bx]         ; pass the next byte
  1550.     out    dx,al
  1551.  
  1552.     inc    bx            ; move the pointer
  1553.     cmp    bx,offset oCircularQueue+MAXQUEUE
  1554.     jb    @F
  1555.     mov    bx,offset oCircularQueue; it wrapped...
  1556.     ;
  1557.     @@:
  1558.     dec    [MIDIoQueueCnt]     ; any queued up data?
  1559.     loopnz    txLoop
  1560.     mov    [lpoMOQueue],bx
  1561. ;
  1562. ; all done with input and output processing. Check for more interrupts
  1563. ;
  1564. second_check:
  1565. ;
  1566. ; in case we received more MIDI data during this routine, check again...
  1567. ;
  1568.         mov     dx,INTRCTLRST
  1569.     xor    dx,[_MVTranslateCode]    ; translate the address
  1570.  
  1571.     in    al,dx            ; get the interrupt status
  1572.     test    al,bISmidi        ; is the interrupt still active?
  1573.     jjnz    mvmidi_int        ; yes, go process it...
  1574. ;
  1575. midiint_done:
  1576.     mov    al,EOI            ; acknowledge the interrupt.
  1577.     cmp    [_IRQNumb],7
  1578.     jbe    @F
  1579.     out    IRQ2ACKREG, al        ; ack the 2nd IRQ controller
  1580.     ;
  1581.     @@:
  1582.     out    IRQ1ACKREG, al        ; ack the 1st IRQ controller
  1583.  
  1584.     cli                ; just in case...
  1585.     ToggleMV101mask         ; make sure the line stays active
  1586. ;
  1587. busy_exit:
  1588.         pop     dx
  1589.     pop    cx
  1590.     pop    bx
  1591.         pop     ax
  1592.     pop    ds
  1593.         iret
  1594.  
  1595. MV101_ISR    endp
  1596.  
  1597. ;
  1598. ;   /*\
  1599. ;---|*|----====< Yamaha_ISR >====----
  1600. ;---|*|
  1601. ;---|*| ISR service routine for the Yamaha 3802 interrupts.
  1602. ;---|*|
  1603. ;   \*/
  1604. ;
  1605. Yamaha_ISR    proc    far
  1606.     push    ds            ; minimal save
  1607.     push    dx
  1608.     push    ax
  1609.  
  1610.     mov    ax, @data        ; establish our DS
  1611.     mov    ds, ax
  1612.  
  1613.     mov    dx, INTRCTLRST
  1614.     in    al, dx            ; acknowledge interrupt
  1615.     test    al, bICmidi        ; our MIDI interrupt?
  1616.     jnz    isourint        ; yes, go do it...
  1617.  
  1618.     pushf
  1619.     call    dword ptr cs:[OldISR]    ; perform the old interrupt
  1620.     jmp    WOOPS_exit
  1621. ;
  1622. isourint:
  1623. ;
  1624. ; we can now process all MIDI interrupts here
  1625. ;
  1626.     push    es
  1627.     push    di
  1628.         cld                             ; fatal to assume
  1629. ;
  1630. ; We will only process interrupt generated input if ProcessControl says so.
  1631. ;
  1632.     test    [ProcessControl],INTINPUT ; Int input?
  1633.     jz    emptyRX           ; polled, check each h/w
  1634. ;
  1635. ; Check for Rx IRQ (means FIFO-Rx went non-empty) empty the FIFO
  1636. ;
  1637.     mov    dx, MDSYSSTAT        ; IRQ Status
  1638.     in    al, dx
  1639.     and    al, RxIRQ        ; FIFO-RX non-empty?
  1640.     jz    emptyRX         ; ..jump if not
  1641.  
  1642.     .errnz    MDIRQCLR-MDSYSSTAT-1
  1643.  
  1644.     inc    dx
  1645.         out     dx,al                   ; flush it...
  1646. ;
  1647. ; get the input queue & load'er up!
  1648. ;
  1649.         mov     ax,ds
  1650.     mov    es,ax
  1651.     mov    di,lpiMIQueue        ; get the input to the queue
  1652.    ;
  1653.    rxISR_05:
  1654.     mov    al, 3            ; 3x
  1655.     mov    dx, MDSYSCTLR
  1656.     out    dx, al
  1657.  
  1658.         mov     dx, MDGROUP4            ; 34 = FIFO-Rx status
  1659.     in    al, dx
  1660.     test    al, RxRDY        ; RxRDY bit?
  1661.     jz    rxISR_10        ; ..jump if FIFO empty
  1662.  
  1663.     mov    dx, MDGROUP6        ; 36 = FIFO-Rx data
  1664.     in    al, dx            ; fetch datum
  1665. ;
  1666. ; Eliminate some overhead! The    MIDI spec requires transmitter send something
  1667. ; every 300 msec. Active Sense (FE) is the standard "nothing for you" byte
  1668. ;
  1669.     test    [_MidiInFilter],MF_ACTSENSE ; filter out active sense
  1670.     jz    @F                ; no, keep it...
  1671.     cmp    al, ACTV_SENSE            ; Active Sense?
  1672.     je    rxISR_05            ; ..ignore it
  1673.     ;
  1674.     @@:
  1675.     cmp    [MIDIiQueueCnt],MAXQUEUE; is it full?
  1676.     jb    @F            ; no, save it
  1677.     inc    _overflow
  1678.         jmp     short rxISR_05
  1679.     ;
  1680.     @@:
  1681.         stosb
  1682.     inc    [MIDIiQueueCnt]     ; one more in...
  1683.     cmp    di,offset iCircularQueue+MAXQUEUE
  1684.     jb    rxISR_05
  1685.     mov    di,offset iCircularQueue
  1686.  
  1687.     jmp    rxISR_05
  1688.    ;
  1689.    rxISR_10:
  1690.     mov    [lpiMIQueue],di     ; get the input to the queue
  1691. ;
  1692. emptyRX:
  1693. ;
  1694. ; Check for Transmitter Empyt IRQ here
  1695. ;
  1696.     test    [ProcessControl],INTOUTPUT ; Int output?
  1697.     jz    endMIDIint           ; no, exit out...
  1698.  
  1699.         mov     dx, MDSYSSTAT           ; IRQ Status
  1700.     in    al, dx
  1701.     and    al, TxIRQ        ; FIFO-Tx became empty?
  1702.     jz    endMIDIint        ; ..jump if not
  1703.  
  1704.         .errnz  MDIRQCLR-MDSYSSTAT-1
  1705.  
  1706.     inc    dx
  1707.         out     dx,al                   ; flush it...
  1708. ;
  1709. ; output any data till done.
  1710. ;
  1711.     cmp    [MIDIoQueueCnt],0    ; any data in the queue?
  1712.     jz    endMIDIint        ; ..jump if not
  1713.  
  1714.         mov     di,lpoMOQueue           ; get the pointer to the queue
  1715.     mov    dx, MDSYSCTLR        ; index to Xmitter
  1716.     mov    al,5
  1717.     out    dx,al
  1718. ;
  1719. ytxLoop:
  1720.     mov    dx, MDGROUP4        ; 54 = FIFO-Tx status
  1721.     in    al, dx
  1722.     test    al, TxRDY        ; TxRDY bit?
  1723.     jz    ytxDone         ; ..jump if FIFO full
  1724.  
  1725.     mov    dx, MDGROUP6        ; 56 = FIFO-Tx data
  1726.     mov    al, [di]
  1727.         out     dx, al                  ; ship datum
  1728.  
  1729.     inc    di            ; move the pointer
  1730.     cmp    di,offset oCircularQueue+MAXQUEUE
  1731.     jb    @F
  1732.     mov    di,offset oCircularQueue; it wrapped...
  1733.     ;
  1734.     @@:
  1735.     dec    [MIDIoQueueCnt]     ; any queued up data?
  1736.     jnz    ytxLoop         ; do as much as possible
  1737. ;
  1738. ytxDone:
  1739.     mov    [lpoMOQueue],di     ; save the ending pointer
  1740. ;
  1741. endMIDIint:
  1742. ;
  1743. ; all int handling is done now, so restore the state & exit home...
  1744. ;
  1745.         pop     di
  1746.     pop    es
  1747.  
  1748.         mov     al, [MDctrl]
  1749.         mov     dx, MDSYSCTLR
  1750.         out     dx, al                  ; restore incoming state
  1751. ;
  1752. WOOPS_reenter:
  1753. ;
  1754. ; flush the data ready IRQ
  1755. ;
  1756.     mov    al,EOI            ; acknowledge at the system level
  1757.     cmp    _IRQNumb,7
  1758.     jbe    @F
  1759.     out    IRQ2ACKREG, al        ; ack the 2nd IRQ controller
  1760.     ;
  1761.     @@:
  1762.     out    IRQ1ACKREG, al        ; ack the 1st IRQ controller
  1763.  
  1764.     ToggleMV101mask         ; make sure the MV101 can generate ints
  1765. ;
  1766. WOOPS_exit:
  1767.         pop     ax
  1768.         pop     dx
  1769.         pop     ds
  1770.     iret
  1771.  
  1772. Yamaha_ISR    endp
  1773.  
  1774. ;   /*\
  1775. ;---|*| end of MIDIA.ASM
  1776. ;   \*/
  1777.  
  1778.     end
  1779.  
  1780.